package ru.amse.tsyganov.jumleditor.view.repr;

import java.util.Collections;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;

import ru.amse.tsyganov.jumleditor.graphicaleditor.Coordinates;
import ru.amse.tsyganov.jumleditor.model.ActivityGraph;
import ru.amse.tsyganov.jumleditor.model.State;
import ru.amse.tsyganov.jumleditor.model.Transition;
import ru.amse.tsyganov.jumleditor.properties.PropertiesList;
import ru.amse.tsyganov.jumleditor.properties.StringProperty;
import ru.amse.tsyganov.jumleditor.validator.Problem;
import ru.amse.tsyganov.jumleditor.view.ModelViewMap;
import ru.amse.tsyganov.jumleditor.view.SelectedItems;
import ru.amse.tsyganov.jumleditor.view.ViewVisitor;
import ru.amse.tsyganov.jumleditor.view.activepoints.ActivePoint;
import ru.amse.tsyganov.jumleditor.view.pref.Fonts;

public class ActivityGraphView<T extends ActivityGraph> extends ViewElement<T> {
	
	private final ModelViewMap modelViewMap = new ModelViewMap();
	
	private final SelectedItems selectedItems = new SelectedItems();
	
	private StateView<? extends State> excludedState = null;
	
	private boolean paintConnectionPoints = false;
	
	public ActivityGraphView(T model) {
		super(model);
	}

	@Override
	public void accept(ViewVisitor v) {
		v.visitActivityGraphView(this);
		
		for (State s : getModel().getContents()) {
			StateView<? extends State> stateView = 
				getModelViewMap().getStatesMap().get(s);
			stateView.accept(v);
		}
	}

	public void prepaintEvent(GC gc, Coordinates coordinates) {
		gc.setFont(Fonts.getDefaultFont());
		
		for (StateView<? extends State> s : getModelViewMap().
				getStatesMap().values()) {
			
			s.prepaintEvent(gc, coordinates);
		}
	}
	
	@Override
	public void paint(GC gc, Coordinates coordinates) {
		assert gc != null;
		
		gc.setAntialias(SWT.ON);
		gc.setFont(Fonts.getDefaultFont());
		
		for (State s : getModel().getContents()) {
			StateView<? extends State> stateView = 
				getModelViewMap().getStatesMap().get(s);
			stateView.paint(gc, coordinates);
		}
		
		for (State s : getModel().getContents()) {
			StateView<? extends State> stateView = 
				getModelViewMap().getStatesMap().get(s);
			stateView.paintTransitions(gc, coordinates);
		}
		
		paintActivePoints(gc, coordinates);
		
		if (paintConnectionPoints) {
			paintConnectionPoints(gc, coordinates);
		}
	}

	@Override
	public List<? extends ActivePoint> getActivePoints() {
		throw new UnsupportedOperationException();
	}
	
	@Override
	public ModelViewMap getModelViewMap() {
		return modelViewMap;
	}
	
	@Override
	public SelectedItems getSelectedItems() {
		return selectedItems;
	}

	@Override
	public ActivityGraphView<T> getActivityGraphView() {
		return this;
	}
	
	public StateView<? extends State> getStateView(int x, int y) {

		for (State s : getModel().getContents()) {
			StateView<? extends State> stateView = getModelViewMap()
					.getStatesMap().get(s);
			if (stateView.getAttractiveRectangle().contains(x, y)) {
				return stateView;
			}
		}
		return null;
	}
	
	public TransitionView<? extends Transition> getTransitionView(int x, int y) {

		for (State s : getModel().getContents()) {
			for (Transition t : s.getStateVertex().getOutgoing()) {

				TransitionView<? extends Transition> transitionView = 
					getModelViewMap().getTransitionsMap().get(t);
				
				if (transitionView.contains(x, y)) {
					return transitionView;
				}
			}
		}
		return null;
	}
	
	public ActivePoint getActivePoint(int x, int y) {

		for (State s : getModel().getContents()) {

			StateView<? extends State> stateView = getModelViewMap()
					.getStatesMap().get(s);

			for (ActivePoint point : stateView.getActivePoints()) {
				if (point.getRectangle().contains(x, y)) {
					return point;
				}
			}

			for (Transition t : s.getStateVertex().getOutgoing()) {
				TransitionView<? extends Transition> transitionView = 
					getModelViewMap().getTransitionsMap().get(t);

				for (ActivePoint point : transitionView.getActivePoints()) {
					if (point.getRectangle().contains(x, y)) {
						return point;
					}
				}
			}
		}
		return null;
	}

	@Override
	public void paintActivePoints(GC gc, Coordinates coordinates) {
		for (StateView<? extends State> s : 
			getSelectedItems().getSelectedStates()) {
			
			s.paintActivePoints(gc, coordinates);
		}
		
		for (TransitionView<? extends Transition> t : 
			getSelectedItems().getSelectedTransitions()) {
			
			t.paintActivePoints(gc, coordinates);
		}
	}
	
	public void paintConnectionPoints(GC gc, Coordinates coordinates) {
		for (State s : getModel().getContents()) {
			StateView<? extends State> view = modelViewMap.getStatesMap().get(s);
			if (view != excludedState) {
				view.paintConnectionPoints(gc, coordinates);
			}
		}
	}
	
	@Override
	public PropertiesList getProperties() {
		throw new UnsupportedOperationException();
	}

	@Override
	public StringProperty getMainProperty() {
		throw new UnsupportedOperationException();
	}

	@Override
	public Point getGuardOutputPoint() {
		throw new UnsupportedOperationException();
	}
	
	public String getClassName() {
		return "ActivityGraphView";
	}

	@Override
	public List<Problem> getInnerProblems() {
		return Collections.emptyList();
	}

	public void setExcludedState(StateView<? extends State> excludedState) {
		this.excludedState = excludedState;
	}

	public void setPaintConnectionPoints(boolean paintConnectionPoints) {
		this.paintConnectionPoints = paintConnectionPoints;
	}

}
